// Learn cc.Class:
//  - https://docs.cocos.com/creator/manual/en/scripting/class.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html

cc.Class({
    extends: cc.Component,
    ctor(){
        this._w = 0;
        this._h = 0;
        this.stepW = 0;
        this.stepH = 0;
        this.level = 5;
        this.lineColor = '#f00';
        this.fontColor = '#f00'
        this.lineW = 3;
        this.max = 0;
        this.blockData = [];
        this.numImgs = {};
        this.selectNumImgs = {};
        this.selects = [];
        this.canClick = true;
        this.testData = [ 
            [1, 2, 1, 2, 1], 
            [2, 1, 2, 1, 2],
            [1, 2, 1, 2, 1], 
            [2, 1, 2, 1, 2],
            [1, 2, 1, 14, 14]
        ]
    },
    properties: {
        pen: cc.Graphics,
        bg: cc.Node,
        blocks: cc.Node,
        block: cc.Prefab,
        score: cc.Label,
        restartBtn: cc.Node,
        gameOverText: cc.Label,
        gameOverBox: cc.Node,
    },
    onLoad () {
        this.gameOverBox.active = false;
        this._w = this.bg.width;
        this._h = this.bg.height;
        cc.resources.loadDir("num", cc.SpriteFrame, (err, assets)=>{
            for(let i=0; i<assets.length; i++){
                this.numImgs[assets[i]._name] = assets[i];
            }
            this.initBlockData();

            if(this.isGameOver()){
                this.gameOver()
            }            
        });
        cc.resources.loadDir("select-num", cc.SpriteFrame, (err, assets)=>{
            for(let i=0; i<assets.length; i++){
                this.selectNumImgs[assets[i]._name] = assets[i];
            }
        });        
        this.initGrid();
        

        this.initBindEvent();
    },
    resetGame(){
        this.blocks.removeAllChildren();
        this.initBlockData();
        this.max = 0;
        this.score.string = this.max;
        this.gameOverBox.active = false;
        if(this.isGameOver()){
            this.gameOver()
        }
    },
    initBindEvent(){
        this.restartBtn.on('touchstart', ()=>{
            this.resetGame();
        })
    },
    initGrid(){
        let stepW = this.stepW = this._w / this.level;
        let stepH = this.stepH = this._h / this.level;
        this.pen.strokeColor = this.lineColor;
        this.pen.lineWidth = this.lineW;
        for(let i=1; i<this.level; i++){
            //x
            this.pen.moveTo(stepW*i, 0)
            this.pen.lineTo(stepW*i, this._h)
            //y
            this.pen.moveTo(0, stepH*i)
            this.pen.lineTo(this._w, stepH*i)
        }
        this.pen.stroke();
    },
    initBlockData(data){
        let arr = [];
        if(!data){
            for(let i=0; i<this.level; i++){
                let arr2 = [];
                for(let j=0; j<this.level; j++){
                    let val = this.getVal(Math.random());
                    let node = this.createBlock({x: i, y: j, val: val})
                    arr2.push({
                        x: i,
                        y: j,
                        val: val,
                        node: node
                    })
                }
                arr.push(arr2)
            }
        }else{
            for(let i=0; i<data.length; i++){
                let arr2 = [];
                for(let j=0; j<data[i].length; j++){
                    let node = this.createBlock({x: i, y: j, val: data[i][j]})
                    arr2.push({
                        x: i,
                        y: j,
                        val: data[i][j],
                        node: node
                    })
                }
                arr.push(arr2)
            }
        }
        this.blockData = arr;
    },
    getVal(rnd){
        if(rnd<0.4 && rnd>=0){
            return 1
        }else if(rnd<0.8 && rnd>=0.4){
            return 2
        }else if(rnd<0.95 && rnd>=0.8){
            return 3
        }else if(rnd<=1 && rnd>=0.95){
            return 4
        }
    },
    createBlock({x, y, val}){
        let block = cc.instantiate(this.block);
        block.width = this.stepW;
        block.height = this.stepH;        
        block.setPosition(cc.v2(x*this.stepW, y*this.stepH))
        let blockChildNode = block.getChildByName('val');
        blockChildNode.setPosition(cc.v2(this.stepW/2, this.stepH/2))
        let label = blockChildNode.getComponent(cc.Label);
        label.string = val;
        block.curPos = {x, y};
        block.toPos = {x, y};
        block.willDestory = false;
        block.isPlus = false;
        let sprite = block.getChildByName('num').getComponent(cc.Sprite);
        sprite.spriteFrame = this.numImgs[val];

        //this.blocks.addChild(block)
        this.blocks.insertChild(block, 0);
        block.on('touchstart', this.clickBlock, this)
        return block
    },
    clickBlock(event){
        if(!this.canClick){
            return false;
        }
        let curNode = event.target;
        let pos = curNode.curPos;
        let arr = this.selects.filter(item=>{
            if(item.x == pos.x && item.y == pos.y){
                return true;
            }else{
                return false;
            }
        });
        console.log(arr.length)
        if(arr.length == 0){
            this.setSelectStyle(false);
            this.selects = [];
            this.selects.push(this.blockData[pos.x][pos.y]);
            this.findSelect(pos.x, pos.y, this.selects)
            if(this.selects.length > 1){
                this.setSelectStyle(true);
            }else{
                this.selects = [];
            }
            this.blockData.forEach(item=>{
                item.forEach(subItem=>{
                    subItem.find = false;
                })
            })
        }else{
            this.destroySelect(pos)
        }
    },
    //设置选中样式
    setSelectStyle(bool){
        if(this.selects == 0){
            return false;
        }
        this.canClick = false;
        if(bool){
            this.selects.forEach(item=>{
                let val = item.val;
                let node = item.node;
                cc.tween(node).by(0.1, {position: cc.v2(0, 8)}).call(()=>{
                    this.canClick = true;
                }).start();
                node.getChildByName('num').getComponent(cc.Sprite).spriteFrame = this.selectNumImgs[val];
            })
        }else{
            this.selects.forEach(item=>{
                let val = item.val;
                let node = item.node;
                cc.tween(node).by(0.1, {position: cc.v2(0, -8)}).call(()=>{
                    this.canClick = true;
                }).start();
                node.getChildByName('num').getComponent(cc.Sprite).spriteFrame = this.numImgs[val];
            })
        }
    },
    //查找相同，并选中
    findSelect(x, y, arr){
        let cur = this.blockData[x][y];
        cur.find = true;
        let val = this.blockData[x][y].val;
        let left = x-1 >= 0 && this.blockData[x-1][y];
        let right = x+1 < this.level && this.blockData[x+1][y];
        let top = y+1 < this.level && this.blockData[x][y+1];
        let bottom = y-1 >= 0 && this.blockData[x][y-1];

        if(left && left.val == val && !left.find){
            arr.push(left)
            this.findSelect(x-1, y, arr)
        }
        if(right && right.val == val && !right.find){
            arr.push(right)
            this.findSelect(x+1, y, arr)
        }
        if(top && top.val == val && !top.find){
            arr.push(top)
            this.findSelect(x, y+1, arr)
        }
        if(bottom && bottom.val == val && !bottom.find){
            arr.push(bottom)
            this.findSelect(x, y-1, arr)
        }        
    },
    //消除
    destroySelect(pos){  
        let index = 0;  
        for(var i=0; i<this.selects.length; i++){
            if(this.selects[i].x == pos.x && this.selects[i].y == pos.y){
                index = i;
                break;
            }
        }
        let target = this.selects.splice(index, 1)[0];
        target.node.clickItem = true;
        let targetPowWord = target.node.convertToWorldSpaceAR(cc.v2(0,0));
        this.canClick = false;
        for(let i=0; i<this.selects.length; i++){
            let curSelectPosWord = this.selects[i].node.convertToWorldSpaceAR(cc.v2(0,0));
            let disPos = targetPowWord.sub(curSelectPosWord)
            let ttAni = cc.tween(this.selects[i].node).by(0.3, {position: disPos})
            ttAni.call(()=>{
                //方块移动之后销毁
                this.selects[i].node.destroy();
                this.selects[i].node = null;
                this.selects[i].val = 0;
                if(i==this.selects.length-1){
                    this.updateBlock(target);
                    this.setBlockDate();
                }
            })
            ttAni.start();
        }
    },
    //更新块的数据
    updateBlock(target){
        target.val = Number(target.val)+1;
        target.node.getChildByName('val').getComponent(cc.Label).string = target.val;
        target.node.getChildByName('num').getComponent(cc.Sprite).spriteFrame = this.numImgs[target.val];
        if(target.val > this.max){
            this.max = target.val;
            if(this.max == 15){
                this.gameOver(true);
            }
        }
    },
    //消除之后重新设置棋盘数据
    setBlockDate(){
        for(let i=0; i<this.blockData.length; i++){
            let curCol = this.blockData[i];
            let n = 0;
            for(let j=0; j<curCol.length; j++){
                let curBlock = curCol[j];
                if(!curBlock.node){
                    //删除被消掉的数据
                    curCol.splice(j, 1)
                    n++;
                    j--;
                    let val = this.getVal(Math.random());
                    let node = this.createBlock({x: i, y: this.level+n, val: val})
                    //填补空位
                    curCol.push({
                        x: i,
                        y: this.level+n,
                        val: val,
                        node: node
                    })                    
                }
            }
        }
        this.moveBlock();
    },
    //将方块移动到正确的位置
    moveBlock(){
        for(let i=0; i<this.blockData.length; i++){
            let curCol = this.blockData[i];
            for(let j=0; j<curCol.length; j++){
                let curBlock = curCol[j];
                let disY = j - curBlock.y;
                let moveY = 0;
                if(curBlock.node.clickItem){
                    moveY -= 8;
                    curBlock.node.clickItem = false;
                }
                if(disY!=0){
                    moveY += this.stepH*disY;
                }
                if(moveY != 0){
                    cc.tween(curBlock.node).by(0.3, {position: cc.v2(0, moveY)}).call(()=>{
                        curBlock.y = j;
                        curBlock.node.curPos.y = j;
                        this.selects = [];
                        this.canClick = true;
                        setTimeout(()=>{
                            if(this.isGameOver()){
                                this.gameOver(true)
                            }
                        }, 16)
                    }).start()
                }
            }
        }
    },
    //显示游戏结束画面
    gameOver(finish){
        if(finish){
            this.gameOverText.string = '合到15'
        }
        this.gameOverBox.active = true;
    },
    //判定并返回游戏是否结束
    isGameOver(){
        let blockData = this.blockData;
        let isOver = true;
        let n = 0;
        for(let i=0; i<this.level; i++){
            for(let j=0; j<this.level; j++){
                let right = blockData[i+1] && blockData[i+1][j].val;
                let top = blockData[i][j+1] && blockData[i][j+1].val
                if(blockData[i][j].val == right || blockData[i][j].val == top){
                    isOver = false;
                    break;
                }else{
                    n++;
                }
            }
        }
        return isOver;
    },  
    start () {

    },

    // update (dt) {},
});
